package com.example.nacos.sentinel.support;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.UUID;

/**
 * @ClassName : WebLogAspect
 * @Description : web日志拦截，记录请求日志，响应日志
 * @Author : tianshuo
 * @Date: 2020-11-12 18:19
 */
@Slf4j
@Aspect
@Component
public class LogAspect {

    private ThreadLocal<Long> startTime = new ThreadLocal<>();
    private ThreadLocal<String> logId = new ThreadLocal<>();
    private static final String TRANCE_ID = "traceId";


    @Pointcut("execution(public * com.example.nacos.sentinel.controller.*.*(..))")
    public void pointcut() {

    }

    @Before("pointcut()")
    public void doBefore(JoinPoint joinPoint) {
        startTime.set(System.currentTimeMillis());
        String uuid = UUID.randomUUID().toString();

        MDC.put(TRANCE_ID, uuid);
        logId.set(uuid);
        //获得类名
        String clazzName = joinPoint.getTarget().getClass().getSimpleName();
        //获得方法名
        String methodName = joinPoint.getSignature().getName();

        // 接收到请求，记录请求内容
        log.info("[{},{}.{}] 请求开始.", logId.get(), clazzName, methodName);

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        HttpServletRequest request = attributes.getRequest();

        // 记录下请求内容
        log.info("[{}] URL : {}", logId.get(), request.getRequestURL().toString());
        log.info("[{}] HTTP_METHOD : {}", logId.get(), request.getMethod());
        log.info("[{}] IP : {}", logId.get(), request.getRemoteAddr());
        log.info("[{}] CLASS_METHOD : {}.{}", logId.get(), clazzName, methodName);
        log.info("[{}] ARGS : {}", logId.get(), Arrays.toString(joinPoint.getArgs()));

    }


    @AfterReturning(value = "pointcut()", returning = "response")
    public void logAfterRunning(JoinPoint joinPoint, Object response) {
        //获得类名
        String clazzName = joinPoint.getTarget().getClass().getSimpleName();
        //获得方法名
        String methodName = joinPoint.getSignature().getName();
        log.info("[{},{}.{}] 请求结束，耗时(毫秒):{},响应信息: \n\t {}. ", logId.get(), clazzName, methodName,
                (System.currentTimeMillis() - startTime.get()), response == null ? "" : response.toString());
        startTime.remove();
        logId.remove();
    }

    /**
     * @description 在连接点执行之后执行的通知（异常通知）
     */
    @AfterThrowing("pointcut()")
    public void doAfterThrowingGame() {
        log.info("[{}] 请求异常,耗时(毫秒):{}", logId.get(), (System.currentTimeMillis() - startTime.get()));
        startTime.remove();
        logId.remove();
        MDC.remove(TRANCE_ID);
    }


}

